package nl.Viewer.Dialogs.DatasetSelection;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.HashMap;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.ProgressMonitor;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import nl.Viewer.Application;
import nl.Viewer.SerializedObjects.Dataset;
import nl.Viewer.SerializedObjects.Modality;
import nl.Viewer.Sessions.SessionManager;

/**
 * This is a dialog to fetch and display a list of datasets, and have the user select one. The dialog will also handle
 * the events for the table on the dialog.
 * 
 * @author Jeroen Verschuur
 * 
 */

public class DatasetSelectionDialog extends JDialog implements Runnable, MouseListener, KeyListener, ActionListener {
   private static final long  serialVersionUID = -1;
   private int                width            = 500, height = 400;
   private boolean            canceled         = false;
   private Dataset            selectedDataset  = null;
   private ArrayList<Dataset> datasets         = null;
   private SessionManager     sessionManager;
   private JTable             table            = null;
   private JButton            okButton;
   private JButton            cancelButton;

   public DatasetSelectionDialog( JFrame owner, SessionManager sessionManager ) throws Exception {
      super( owner, "Select a dataset", true );

      this.sessionManager = sessionManager;

      this.setLayout( new BorderLayout() );
      this.setSize( width, height );
      //this.setMinimumSize( this.getSize() );

      this.setLocationRelativeTo( owner );

      // start a processing thread to fetch the dataset list
      new Thread( this ).start();
   }

   public void run() {
      // show a progress bar
      ProgressMonitor monitor = new ProgressMonitor( this, "Getting list of datasets ...", null, 0, 1 );
      monitor.setMillisToPopup( 0 );
      monitor.setMillisToDecideToPopup( 0 );

      monitor.setProgress( 0 );

      try {
         datasets = (ArrayList<Dataset>)sessionManager.getDatasets();

         if( datasets.size() == 0 ) {
            Application.showErrorMessage( "No datasets available",
                  "There are no datasets available or visible on this server" );
            setVisible( false );
            return;
         }

      }
      catch( Exception e ) {
         // TODO: print message
         e.printStackTrace();
         setVisible( false );
         return;
      }
      finally {
         monitor.setProgress( 1 );
      }

      if( monitor.isCanceled() ) {
         canceled = true;

         setVisible( false );
         return;
      }

      // create the table
      Object[][] rowData = new Object[ datasets.size() ][];
      int i = 0;
      for( Dataset d : datasets ) {
         // modalities
         String modalityString = "";

         HashMap<Integer, Modality> modalities = d.getModalities();

         for( Modality m : modalities.values() ) {
            if( modalityString.length() > 0 ) {
               modalityString += ", ";
            }
            modalityString += m.getName();
         }
         if( modalityString.length() == 0 ) {
            modalityString = "None";
         }

         rowData[i++] = new Object[] { d.name, modalityString, d.description };
      }

      initializeComponents( rowData );
      validate();
   }

   private void initializeComponents( Object[][] rowData ) {
      final String[] columnNames = new String[] { "Dataset", "Modalities", "Description" };
      TableModel tm = new DatasetSelectionTableModel( columnNames, rowData );

      table = new JTable( tm );

      // table.setRowHeight((3*table.getFontMetrics(table.getFont()).getHeight())+3);
      //table.setDefaultRenderer( String.class, new MultiLineCellRenderer( this ) );
      table.addMouseListener( this );
      this.addKeyListener( this );

      table.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
      table.getSelectionModel().setSelectionInterval( 0, 0 );
      JScrollPane scrollPane = new JScrollPane( table );

      getContentPane().setLayout( new BorderLayout() );
      getContentPane().add( scrollPane, BorderLayout.CENTER );

      // add ok and cancel panel
      JPanel buttons = new JPanel();
      okButton = new JButton( "OK" );
      cancelButton = new JButton( "Cancel" );
      okButton.addActionListener( this );
      cancelButton.addActionListener( this );
      buttons.add( okButton );
      buttons.add( cancelButton );

      getContentPane().add( buttons, BorderLayout.PAGE_END );
   }

   public boolean isCanceled() {
      return canceled;
   }

   public Dataset getSelectedDataset() {
      return selectedDataset;
   }

   private void selectDataset( int tableRowNum ) {
      if( tableRowNum >= datasets.size() ) {
         selectedDataset = null;
      } else {
         selectedDataset = datasets.get( tableRowNum );
      }
      setVisible( false );
   }

   public void mousePressed( MouseEvent e ) {
   }

   public void mouseReleased( MouseEvent e ) {
   }

   public void mouseExited( MouseEvent e ) {
   }

   public void mouseEntered( MouseEvent e ) {
   }

   public void mouseClicked( MouseEvent e ) {
      if( e.getClickCount() == 2 ) {
         int row = table.getSelectedRow();
         selectDataset( row );
         e.consume();
      }
   }

   public void keyPressed( KeyEvent e ) {
   }

   public void keyReleased( KeyEvent e ) {
      // KeyListener was added for the table, enter-pressed should trigger the selected dataset to be picked
      if( e.getKeyCode() == KeyEvent.VK_ENTER ) {
         selectDataset( table.getSelectedRow() );
         e.consume();
      }
   }

   public void keyTyped( KeyEvent e ) {
   }

   public void actionPerformed( ActionEvent e ) {
      if( e.getSource() == okButton ) {
         selectDataset( table.getSelectedRow() );
      } else if( e.getSource() == cancelButton ) {
         canceled = true;
         selectedDataset = null;
         setVisible( false );
      }
   }
}

/**
 * A custom table cell renderer for the dialog selection
 * 
 * @author Jeroen Verschuur
 * 
 */

class MultiLineCellRenderer extends JTextArea implements TableCellRenderer {
   private static final long serialVersionUID = -1;
   DatasetSelectionDialog    dialog;

   public MultiLineCellRenderer( DatasetSelectionDialog dialog ) {
      super();
      this.dialog = dialog;
      setEditable( false );
      setLineWrap( true );
      setWrapStyleWord( true );
      setOpaque( true );
   }

   public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus,
         int row, int column ) {
      if( isSelected ) {
         setBackground( table.getSelectionBackground() );
         setForeground( table.getSelectionForeground() );
      } else {
         setBackground( table.getBackground() );
         setForeground( table.getForeground() );
      }
      setFont( table.getFont() );
      setText( value.toString() );
      this.setSize( new Dimension(100, 100) );
      this.setRows( 10 );

      return this;
   }
}

/**
 * A custom table model for the selection table
 * 
 * @author Jeroen Verschuur
 * 
 */

class DatasetSelectionTableModel extends AbstractTableModel {
   private static final long serialVersionUID = -1;
   String[]                  columnNames;
   Object[][]                rowData;

   public DatasetSelectionTableModel( String[] columnNames, Object[][] rowData ) {
      this.columnNames = columnNames;
      this.rowData = rowData;
   }

   public String getColumnName( int col ) {
      return columnNames[col].toString();
   }

   public int getRowCount() {
      return rowData.length;
   }

   public int getColumnCount() {
      return columnNames.length;
   }

   public Object getValueAt( int row, int col ) {
      return rowData[row][col];
   }

   public boolean isCellEditable( int row, int col ) {
      return false;
   }

   public void setValueAt( Object value, int row, int col ) {
      return;
      /*
       * rowData[row][col] = value; fireTableCellUpdated(row, col);
       */
   }

   public Class<?> getColumnClass( int columnIndex ) {
      // if( columnIndex == 3 )
      // return Boolean.class;
      return String.class;
   }

}
